package com.northone.statistics.widget;

import android.content.Context;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.ViewDragHelper;
import android.support.v4.widget.ViewDragHelper.Callback;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;

import com.nineoldandroids.view.ViewHelper;

/**
 * 自定义拖拽控件 .
 * 
 * @author xiaoyu
 * 
 */
public class DragLayout extends FrameLayout {
	private ViewDragHelper mHelper;
	private ViewGroup leftContent;
	private ViewGroup mainContent;
	private int width;
	private int height;
	private int mRange;
	// 初始化状态，默认设置为关闭状态 。
	private Status status = Status.Close;

	private onDragChangeListener dragChangeListener;

	/* 创建状态的枚举。 */
	public static enum Status {
		Close, Open, Draging
	}

	public interface onDragChangeListener {
		void onClose();

		void onOpen();

		void onDraging(float percent);
	}

	public Status getStatus() {
		return status;
	}

	public void setStatus(Status status) {
		this.status = status;
	}

	public onDragChangeListener getDragChangeListener() {
		return dragChangeListener;
	}

	public void setDragChangeListener(onDragChangeListener dragChangeListener) {
		this.dragChangeListener = dragChangeListener;
	}
	// 重写三个构造方法 。
	public DragLayout(Context context) {
		this(context, null);
	}

	public DragLayout(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
	}

	public DragLayout(Context context, AttributeSet attrs, int defStyleAttr) {
		super(context, attrs, defStyleAttr);
		/**
		 * 1.创建 ViewDragHelper 辅助类 。
		 * forParent:父类的容器。sensitivity:敏感度,越大越敏感.1.0f是默认值。 Callback:事件回调
		 */
		mHelper = ViewDragHelper.create(this, 1.0f, callback);
	}

	/* 3.重写回调的方法 。 */
	Callback callback = new Callback() {
		/*
		 * 接收处理的结果。 返回值, 决定了child是否可以被拖拽 child:被用户拖拽的子View, pointerId:多点触摸的手指id
		 */
		public boolean tryCaptureView(View child, int pointerId) {
			return true;
		};
		
		/* 返回拖拽的范围，一个大于0的值。决定了动画的执行时长和水平方向是否可以滑开。 */
		public int getViewHorizontalDragRange(View child) {
			return mRange;
		};

		/*
		 * 修正子View水平方向的位置，还没有发生真正的移动 ,返回值决定了View将会移动到的位置。
		 * child是被拖拽的子View,left是建议移动到的位置,dx是新位置与旧位置的差值。
		 */
		public int clampViewPositionHorizontal(View child, int left, int dx) {
			if (child == mainContent) {
				left = fixLeft(left);
			}
			return left;
		};

		/* 当控件位置变化时调用，可以作：伴随动画，更新状态，事件回调。 */
		public void onViewPositionChanged(View changedView, int left, int top,
				int dx, int dy) {
			if (changedView == leftContent) {
				// 1.放回原来的位置 。
				leftContent.layout(0, 0, width, height);
				// 2.把左面板发生的变化量dx传递给主面板 。
				int newLeft = mainContent.getLeft() + dx;
				newLeft = fixLeft(newLeft);
				mainContent.layout(newLeft, 0, newLeft + width, height);
			}
			dispatchDragevent();
			invalidate();
		};

		/**
		 * @param releasedChild
		 *            被释放的孩子
		 * @param xvel
		 *            释放时X方向的速度
		 * @param yvel
		 *            释放时Y方向的速度
		 */
		public void onViewReleased(View releasedChild, float xvel, float yvel) {
			// 当childView被释放时，希望做的事情——执行打开/关闭动画，更新状态
			boolean scrollRight = xvel > 100.0f;
			boolean scrollLeft = xvel < -100.0f;
			if (Math.abs(xvel) > Math.abs(yvel)) {
				if (scrollRight) {
					// 打开 。
					open();
				} else if (scrollLeft) {
					// 关闭 。
					close();
				}else if (mainContent.getLeft() > mRange * 0.5f) {
					open();
				} else {
					// 关闭
					close();
				}
			}
		};
	};
	/** 2.转交触摸事件:让ViewDragHelper与当前类DragLayout关联。 */
	@Override
	public boolean onInterceptTouchEvent(MotionEvent ev) {
		// 由ViewDragHelper判断触摸事件是否该拦截 。
		return mHelper.shouldInterceptTouchEvent(ev);
	}

	/** 分发拖拽事件，伴随动画，更新状态。 */
	protected void dispatchDragevent() {
		float percent = mainContent.getLeft() * 1.0f / mRange;
		
		if (dragChangeListener != null) {
			dragChangeListener.onDraging(percent);
		}
		
		Status lastStatus = status;
		// 更新状态 。
		status = updateStatus(percent);
		if (status != lastStatus && dragChangeListener != null) {
			if (status == Status.Open) {
				dragChangeListener.onOpen();
			}else if (status == Status.Close) {
				dragChangeListener.onClose();
			}
		}
		animViews(percent); // 调用执行动画的方法 。
	}

	private Status updateStatus(float percent) {
		if (percent == 0) {
			// 关闭状态 。
			return Status.Close;
		} else if (percent == 1) {
			// 打开状态 。
			return Status.Open;
		}
		return Status.Draging;
	}

	/** 执行动画 。 */
	private void animViews(float percent) {
		// 左面板：缩放动画，平移动画，透明度动画。
		ViewHelper.setScaleX(leftContent, evaluate(percent, 0.5f, 1.0f));
		ViewHelper.setScaleY(leftContent, evaluate(percent, 0.5f, 1.0f));
		// 平移动画 。
		ViewHelper.setTranslationX(leftContent,
				evaluate(percent, -width / 2.0f, 0));
		// 透明度动画
		ViewHelper.setAlpha(leftContent, evaluate(percent, 0.2f, 1.0f));
		// 主面板：缩放动画。 1.0-->0.8
		ViewHelper.setScaleX(mainContent, evaluate(percent, 1.0f, 0.8f));
		ViewHelper.setScaleY(mainContent, evaluate(percent, 1.0f, 0.8f));
		// 背景：亮度变化 。
		int color = (Integer) evaluateColor(percent, Color.BLACK,
				Color.TRANSPARENT);
		getBackground().setColorFilter(color, PorterDuff.Mode.SRC_OVER);
	}

	public void close() {
		close(true);
	}

	public void close(boolean isSmooth) {
		if (isSmooth) {
			// 平滑动画 。1.触发一个平滑动画 。
			if (mHelper.smoothSlideViewTo(mainContent, 0, 0)) {
				// 需要重绘界面 。参数传子View所在的容器 this 。
				ViewCompat.postInvalidateOnAnimation(this);
			}
		} else {
			mainContent.layout(0, 0, width, height);
		}
	}

	public void open() {
		open(true);
	}

	public void open(boolean isSmooth) {
		if (isSmooth) {
			// 平滑动画 。1.触发一个平滑动画 。
			if (mHelper.smoothSlideViewTo(mainContent, mRange, 0)) {
				// 需要重绘界面 。参数传子View所在的容器 this 。
				ViewCompat.postInvalidateOnAnimation(this);
			}
		} else {
			mainContent.layout(mRange, 0, mRange + width, height);
		}
	}

	// 维持动画的继续 。
	@Override
	public void computeScroll() {
		if (mHelper.continueSettling(true)) {
			ViewCompat.postInvalidateOnAnimation(this);
		}
	}

	protected int fixLeft(int left) {
		if (left < 0) {
			return 0;
		} else if (left > mRange) {
			return mRange;
		}
		return left;
	}

	/** 处理手势滑动事件 , 由ViewDragHelper处理事件 。 */
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		try {
			mHelper.processTouchEvent(event);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return true;
	}

	/** 当控件尺寸变化的时候调用该方法 */
	@Override
	protected void onSizeChanged(int w, int h, int oldw, int oldh) {
		super.onSizeChanged(w, h, oldw, oldh);
		width = getMeasuredWidth();
		height = getMeasuredHeight();

		mRange = (int) (width * 0.6);
	}

	@Override
	protected void onFinishInflate() {
		super.onFinishInflate();
		if (getChildCount() < 2) {
			throw new IllegalStateException(
					"Your viewgroup must have 2 children。");
		}
		if (!(getChildAt(0) instanceof ViewGroup)
				|| !(getChildAt(1) instanceof ViewGroup)) {
			throw new IllegalStateException("孩子必须是ViewGroup的子类");
		}
		leftContent = (ViewGroup) getChildAt(0);
		mainContent = (ViewGroup) getChildAt(1);
	}
	
	public Float evaluate(float fraction, Number startValue, Number endValue) {
		float startFloat = startValue.floatValue();
		return startFloat + fraction * (endValue.floatValue() - startFloat);
	}

	/* 颜色过渡器。 */
	public Object evaluateColor(float fraction, Object startValue,
			Object endValue) {
		int startInt = (Integer) startValue;
		int startA = (startInt >> 24) & 0xff;
		int startR = (startInt >> 16) & 0xff;
		int startG = (startInt >> 8) & 0xff;
		int startB = startInt & 0xff;

		int endInt = (Integer) endValue;
		int endA = (endInt >> 24) & 0xff;
		int endR = (endInt >> 16) & 0xff;
		int endG = (endInt >> 8) & 0xff;
		int endB = endInt & 0xff;

		return (int) ((startA + (int) (fraction * (endA - startA))) << 24)
				| (int) ((startR + (int) (fraction * (endR - startR))) << 16)
				| (int) ((startG + (int) (fraction * (endG - startG))) << 8)
				| (int) ((startB + (int) (fraction * (endB - startB))));
	}
}
